package blobDetector;

import java.util.Vector;

public class BlobDetector {
	
	float[]values;
	int w, h;
	boolean[] checked;
	boolean[] borders;
	public Vector<Blob> blobs;
	float minIso=0;
	float maxIso=200;

	public BlobDetector(int w, int h) {
		this.w = w;
		this.h = h;
		blobs=new Vector<Blob>();
	}
	
	public void setValues(float[][] vals) {
		int index=0;
		values=new float[w*h];
		for (int y = 0; y < vals[0].length; y++) {
			for (int x = 0; x < vals.length; x++) {
				values[index]=vals[x][y];
				index++;
			}
		}
	}
	
	public void setValues(int[][] vals) {
		int index=0;
		values=new float[w*h];
			for (int y = 0; y < vals[0].length; y++) {
				for (int x = 0; x < vals.length; x++) {
					values[index]=vals[x][y];
				index++;
			}
		}
	}

	public void setValues(float[] vals) {
		values=vals;
	}

	public void setValues(int[] vals) {
		values = new float[w * h];
		for (int i = 0; i < vals.length; i++) {
			values[i] = vals[i];
		}
	}
	
	public int getNbInt(int position,int dir){
		int index=getNb(position,dir);
		if (outOfArray(index))return -1;
		return index;
	}
	public int getNb(int position,int dir){
		if (dir==0)return position+w;
		if (dir==1)return position+w+1;
		if (dir==2)return position+1;
		if (dir==3)return position-w+1;
		if (dir==4)return position-w;
		if (dir==5)return position-w-1;
		if (dir==6)return position-1;
		if (dir==7)return position+w-1;
		return -1;
	}
	public boolean outOfArray(int index){
		int x=getX(index);
		int y=getY(index);
		if (x<0||x>=w)return true;
		if (y<0||y>=h)return true;
		return false;
	}
	public boolean checkIfInside(int i) {
		float v=values[i];
		if (v > maxIso||v<minIso) {
			return false;
		} else {
			return true;
		}
	}

	public boolean checkIfBorder(int index) {
		if (checkIfInside(index) == false)
			return false;// too bright
		else {
			int x=getX(index);
			int y=getY(index);
			if (x==0||x==w-1)return true;
			if (y==0||y==h-1)return true;
			for (int i = 0; i < 8; i += 2) {
				int nbIndex=getNbInt(index,i);
				if (nbIndex<0|| !checkIfInside(nbIndex)) {// bright nb
					return true;
				}
			}
		}
		return false;
	}
	
	public int inverseDirection(int i) {
		return (i + 4) % 8;
	}
	
	public int getNextDirection(int cellIndex,int lastDir) {
		int cDir = lastDir + 1;
		cDir = cDir % 8;
		int nbIndex=getNbInt(cellIndex,cDir);
		int counter = 0;
		while (counter < 8 && (nbIndex< 0 || !borders[nbIndex])) {
			cDir++;
			cDir = cDir % 8;
			nbIndex =getNbInt(cellIndex,cDir);
			counter++;
		}
		if (counter >= 8)
			return -1;
		return cDir;
	}
	
	
	
	public float getValue(int x, int y) {
		return values[getIndex(x,y)];
	}
	public int getX(int index){
		return index%w;
	}
	public int getY(int index){
		return index/w;
	}
	public int getIndex(int x, int y){
		return y*w+x;
	}
	
	public void calculateBlobs(float iso) {
		
		checked=new boolean[values.length];
		borders=new boolean[values.length];
		blobs = new Vector<Blob>();
		for (int index = 0; index < checked.length; index++) {
			checked[index]=false;
		}
		for (int index = 0; index < checked.length; index++) {
			borders[index]=checkIfBorder(index);
		}
		for (int index = 0; index < values.length; index++) {
			if (borders[index] && !checked[index]) {
				// finding starting direction
				int startDir=-1;
				for (int i = 0; i < 8; i++) {
					int nb = getNbInt(index,i);
					if (nb<0||!checkIfInside(nb) ) {
						startDir = i;
						break;
					}
				}
				// looping around the blob
				int nextIndex=index;
				int nextDir = inverseDirection(startDir);
				Blob blob = new Blob();
				do {
					int inverseDir = inverseDirection(nextDir);
					nextDir = getNextDirection(nextIndex,inverseDir);
					if (nextDir == -1) {
						// single Pixel
					} else {
						nextIndex =getNbInt(nextIndex,nextDir);
					}
					if (!checked[nextIndex]) {
						checked[nextIndex]=true;
						blob.add(getX(nextIndex),getY(nextIndex));
					}
				} while (nextIndex != index);
				if (blob.borders.size() > 1) {
					blobs.add(blob);
				}
			}
		}
	}
	
	
	

	public Vector<Blob> getBlobs() {
		return blobs;
	}
}
